import sys

import pygame

from src.base_elements.landscape import Steel
from src.base_elements.props import (
    BaseProp,
    UpgradeProp,
    UltimateUpgradeProp,
    HealthProp,
    ReinforceProp,
    BoomProp,
    PauseProp, ShieldProp
)
from src.base_elements.tanks import PlayerTank, TANK_MAP, Shield, Enemy1Tank, Enemy2Tank, Enemy3Tank, Enemy4Tank, \
    EnemyPropTank
from src.constants import Player, Direction, EnemyTankSpawn, ExplosionType, GameScreen
from src.custom_pygame.sprite import CustomGroup, AnimationSprite
from src.utils.maps import MapGenerator


class GameInitializer:

    def __init__(self):
        # 游戏窗口参数
        self.title = "War of Tanks"
        self.width = 750
        self.height = 630
        self.screen = None

        # 手柄设备
        self.joystick = None

        # 当前游戏阶段
        self.step = GameScreen.TRANSITION

        # 是否已在过场界面
        self.is_transition = False
        # 过场界面开始时间
        self.transition_start_time = 0
        # 过场界面持续时间，单位：毫秒
        self.transition_duration = 3000
        # TODO 增加跳过过场界面的逻辑
        self.skip_transition = False

        # 是否生成关卡
        self.should_generate_stage = False
        # 当前游戏所处关卡
        self.current_stage_num = 1
        # 每关会出现的总敌方坦克列表
        self.all_enemy_tanks = []

        # 是否游戏结束
        self.is_game_over = False
        # 游戏结束倒计时开始时间
        self.game_over_countdown_start_time = 0
        # 游戏结束倒计时时长, 单位：毫秒
        self.game_over_countdown = 2000

        # 初始化结算相关变量
        self._init_resulting()
        
        # 玩家一坦克
        self.player1_tank = None
        # 玩家一生命数
        self.player1_live_count = 5
        # 玩家一分数
        self.player1_score = 0
        # 玩家一生命数精灵
        self.player1_live_count_sprite = pygame.sprite.Sprite()
        # 玩家二坦克
        self.player2_tank = None
        # 玩家二生命数
        self.player2_live_count = 5
        # 玩家二分数
        self.player2_score = 0
        # 玩家二生命数精灵
        self.player2_live_count_sprite = pygame.sprite.Sprite()

        # 初始化精灵组
        self._init_group()

        # 玩家坦克移动延时，该参数的作用是为了在玩家松开移动键后，坦克不会立刻停止，防止坦克卡地形。
        self.player1_move_delay = 0
        self.player2_move_delay = 0
        self.player1_last_direction = None
        self.player2_last_direction = None
        # 是否暂停敌方坦克移动
        self.is_pause_moving = False
        # 暂停开始的时间
        self.pause_start_time = 0
        # 暂停时长, 单位：毫秒
        self.pause_duration = 15000

        # 敌方坦克生成时间间隔, 单位：毫秒
        self.enemy_tank_appear_interval = 2000
        # 敌方坦克上一次生成的时间
        self.last_enemy_tank_appear_time = 0
        # 敌方坦克生成点索引
        self.enemy_tank_spawn_index = 1

        self._init_pygame()
        self._init_images()
        self._init_sounds()
        self._init_font()

    def _init_group(self, is_first=True):
        # 玩家基地
        self.home = None
        # 地形组
        self.landscape_group = None
        # 禁止道具生成的地形
        self.prop_forbidden_landscape_group = None
        if is_first:
            # 所有坦克组
            self.tank_group = pygame.sprite.Group()
            # 玩家坦克组
            self.player_tank_group = pygame.sprite.Group()
        # 敌军坦克组
        self.enemy_tank_group = pygame.sprite.Group()
        # 护盾组
        self.shield_group = pygame.sprite.Group()
        # 玩家子弹组
        self.player_bullet_group = CustomGroup()
        # 敌军子弹组
        self.enemy_bullet_group = CustomGroup()
        # 道具组
        self.prop_group = pygame.sprite.Group()
        # 有碰撞体积的动画组
        self.collidable_animation_group = pygame.sprite.Group()
        # 没有碰撞体积的动画组
        self.non_collidable_animation_group = pygame.sprite.Group()
        # 敌军坦克标志组
        self.enemy_icon_group = CustomGroup()
        # 计分板精灵组
        self.score_board_group = pygame.sprite.Group()
        # 游戏结束图片精灵
        self.game_over_sprite = pygame.sprite.Sprite()
        # 游戏结束图片组
        self.game_over_group = pygame.sprite.Group()

    def _init_resulting(self):
        # 是否已在结算界面
        self.is_resulting = False
        # 上一次结算动画帧切换时间
        self.last_resulting_animation_time = 0
        # 结算动画间隔时间，单位：毫秒
        self.resulting_animation_duration = 200
        # 结算到哪类敌军坦克的索引
        self.resulting_idx = 0
        # 用于记录某一类型的敌军坦克是否已经结算完毕，只有当玩家一和玩家二的同一类型的敌军坦克都结算完毕时，才会开始下一个类型的敌军坦克的结算
        self.is_player1_resulted = False
        self.is_player2_resulted = False
        # 是否更新总分
        self.should_update_total_score = False
        # 是否开始新的关卡
        self.should_start_new_stage = False
        # 玩家一和玩家二当前关卡的分数
        self.player1_stage_score = 0
        self.player2_stage_score = 0
        # 玩家一和玩家二结算缓存。由于结算中有数字从小到大的动画，所以需要一个变量来缓存变化中的数字
        self.p1_resulting_temp_count = 0
        self.p2_resulting_temp_count = 0
        # 玩家一和玩家二击杀信息，以及击杀数量和分数的渲染坐标
        self.p1_kill_info = {
            Enemy1Tank: {
                "kill_count": 0,
                "kill_count_rect": (270, 266),
                "kill_score_rect": (104, 266)
            },
            Enemy2Tank: {
                "kill_count": 0,
                "kill_count_rect": (270, 335),
                "kill_score_rect": (104, 335)
            },
            Enemy3Tank: {
                "kill_count": 0,
                "kill_count_rect": (270, 404),
                "kill_score_rect": (104, 404)
            },
            Enemy4Tank: {
                "kill_count": 0,
                "kill_count_rect": (270, 474),
                "kill_score_rect": (104, 474)
            },
        }
        self.p2_kill_info = {
            Enemy1Tank: {
                "kill_count": 0,
                "kill_count_rect": (450, 266),
                "kill_score_rect": (588, 266)
            },
            Enemy2Tank: {
                "kill_count": 0,
                "kill_count_rect": (450, 335),
                "kill_score_rect": (588, 335)
            },
            Enemy3Tank: {
                "kill_count": 0,
                "kill_count_rect": (450, 404),
                "kill_score_rect": (588, 404)
            },
            Enemy4Tank: {
                "kill_count": 0,
                "kill_count_rect": (450, 474),
                "kill_score_rect": (588, 474)
            },
        }

    def _init_pygame(self):
        pygame.init()

        # 创建游戏窗口
        self.screen = pygame.display.set_mode(size=(self.width, self.height))
        pygame.display.set_caption(self.title)

    def _init_images(self):
        # 背景图片
        self.background_image = pygame.image.load("assets/images/background.png")
        self.background2_image = pygame.image.load("assets/images/background2.png")
        self.background3_image = pygame.image.load("assets/images/background3.png")
        # 敌方坦克出现动画的图片
        self.appear1_image = pygame.image.load("assets/images/animation/appear_1.png")
        self.appear2_image = pygame.image.load("assets/images/animation/appear_2.png")
        self.appear3_image = pygame.image.load("assets/images/animation/appear_3.png")
        self.appear4_image = pygame.image.load("assets/images/animation/appear_4.png")
        self.appear_images = [self.appear1_image, self.appear2_image, self.appear3_image, self.appear4_image]
        # 组成爆炸动画的图片
        self.explosion1_image = pygame.image.load("assets/images/animation/explosion_1.png")
        self.explosion2_image = pygame.image.load("assets/images/animation/explosion_2.png")
        self.explosion3_image = pygame.image.load("assets/images/animation/explosion_3.png")
        self.explosion4_image = pygame.image.load("assets/images/animation/explosion_4.png")
        self.explosion5_image = pygame.image.load("assets/images/animation/explosion_5.png")
        self.small_explosion_images = [self.explosion1_image, self.explosion2_image, self.explosion3_image]
        self.large_explosion_images = [self.explosion1_image, self.explosion2_image, self.explosion3_image,
                                       self.explosion4_image, self.explosion5_image, self.explosion4_image]
        # 积分板相关图片
        self.player_icon_image = pygame.image.load("assets/images/scoreboard/player_icon.png")
        self.enemy_icon_image = pygame.image.load("assets/images/scoreboard/enemy_icon.png")
        self.flag_image = pygame.image.load("assets/images/scoreboard/flag.png")
        self.arrow1_image = pygame.image.load("assets/images/scoreboard/arrow1.png")
        self.arrow2_image = pygame.image.load("assets/images/scoreboard/arrow2.png")
        # 敌军坦克图片
        self.enemy1_tank_image = pygame.image.load("assets/images/scoreboard/enemy1_tank.png")
        self.enemy2_tank_image = pygame.image.load("assets/images/scoreboard/enemy2_tank.png")
        self.enemy3_tank_image = pygame.image.load("assets/images/scoreboard/enemy3_tank.png")
        self.enemy4_tank_image = pygame.image.load("assets/images/scoreboard/enemy4_tank.png")
        # 游戏结束英文图片
        self.game_over_image = pygame.image.load("assets/images/game_over.png")

    def _init_sounds(self):
        # 子弹碰撞的声音
        self.bullet_impact_sound = pygame.mixer.Sound("assets/sounds/bullet_impact.ogg")
        # 爆炸的声音
        self.tank_explosion_sound = pygame.mixer.Sound("assets/sounds/tank_explosion.ogg")
        # 射击的声音
        self.gunfire_sound = pygame.mixer.Sound("assets/sounds/gunfire.wav")
        # 激活道具的声音
        self.activate_common_prop_sound = pygame.mixer.Sound("assets/sounds/activate_common_prop.ogg")
        self.activate_health_prop_sound = pygame.mixer.Sound("assets/sounds/activate_health_prop.ogg")
        self.activate_pause_prop_sound = pygame.mixer.Sound("assets/sounds/activate_pause_prop.ogg")
        # 结算的声音
        self.result_sound = pygame.mixer.Sound("assets/sounds/result.ogg")
        # 游戏开始时的声音
        self.start_sound = pygame.mixer.Sound("assets/sounds/start.wav")
        # 游戏结束时的声音
        self.game_over_sound = pygame.mixer.Sound("assets/sounds/game_over.ogg")

    def _init_font(self):
        font_path = "assets/fonts/ChillPixels-Maximal.otfx"
        try:
            self.my_font = pygame.font.Font(font_path, 18)
            self.my_result_font = pygame.font.Font(font_path, 22)
        except FileNotFoundError:
            print(f"警告：未找到字体文件 {font_path}，将使用默认字体")
            self.my_font = pygame.font.Font(None, 25)
            self.my_result_font = pygame.font.Font(None, 30)

    def _check_joystick(self):
        if pygame.joystick.get_count() > 0:
            self.joystick = pygame.joystick.Joystick(0)
            self.joystick.init()
            print(f"已连接手柄: {self.joystick.get_name()}")

    def _generate_stage_loading_screen(self):
        if self.step is GameScreen.TRANSITION and not self.is_transition:
            self.is_transition = True
            self.transition_start_time = pygame.time.get_ticks()
            self.screen.blit(self.background2_image, (0, 0))
            stage_title_image = self.my_font.render(f"STAGE   {self.current_stage_num}", False, (10, 10, 10))
            stage_title_image_rect = stage_title_image.get_rect(center=(375, 315))
            self.screen.blit(stage_title_image, stage_title_image_rect)
            self.start_sound.play()
            pygame.display.flip()
        if self.step is GameScreen.TRANSITION and \
                pygame.time.get_ticks() - self.transition_start_time > self.transition_duration:
            self.step = GameScreen.IN_GAME
            self.should_generate_stage = True

    def _generate_score_board(self):
        # 生成敌军坦克图标
        for y in range(10):
            for x in range(2):
                enemy_icon_sprite = pygame.sprite.Sprite()
                enemy_icon_sprite.image = self.enemy_icon_image
                enemy_icon_sprite.rect = enemy_icon_sprite.image.get_rect(topleft=(670 + x * 20, 40 + y * 20))
                self.enemy_icon_group.add(enemy_icon_sprite)

        # 生成玩家坦克图标
        player1_icon_sprite = pygame.sprite.Sprite()
        player1_icon_sprite.image = self.player_icon_image
        player1_icon_sprite.rect = player1_icon_sprite.image.get_rect(topleft=(670, 360))
        self.score_board_group.add(player1_icon_sprite)
        player2_icon_sprite = pygame.sprite.Sprite()
        player2_icon_sprite.image = self.player_icon_image
        player2_icon_sprite.rect = player2_icon_sprite.image.get_rect(topleft=(670, 440))
        self.score_board_group.add(player2_icon_sprite)
        # 生成玩家标识
        p1_sprite = pygame.sprite.Sprite()
        p1_sprite.image = self.my_font.render("Player I", False, (30, 30, 30))
        p1_sprite.rect = p1_sprite.image.get_rect(topleft=(655, 335))
        self.score_board_group.add(p1_sprite)
        p2_sprite = pygame.sprite.Sprite()
        p2_sprite.image = self.my_font.render("Player II", False, (30, 30, 30))
        p2_sprite.rect = p2_sprite.image.get_rect(topleft=(655, 415))
        self.score_board_group.add(p2_sprite)
        # 生成玩家生命计数
        self.player1_live_count_sprite.image = \
            self.my_font.render(str(self.player1_live_count), False, (10, 10, 10))
        self.player1_live_count_sprite.rect = self.player1_live_count_sprite.image.get_rect(topleft=(700, 363))
        self.score_board_group.add(self.player1_live_count_sprite)
        self.player2_live_count_sprite.image = \
            self.my_font.render(str(self.player2_live_count), False, (10, 10, 10))
        self.player2_live_count_sprite.rect = self.player2_live_count_sprite.image.get_rect(topleft=(700, 443))
        self.score_board_group.add(self.player2_live_count_sprite)
        # 生成关卡旗帜
        flag_sprite = pygame.sprite.Sprite()
        flag_sprite.image = self.flag_image
        flag_sprite.rect = flag_sprite.image.get_rect(topleft=(670, 40 + 24 * 20))
        self.score_board_group.add(flag_sprite)
        stage_number_sprite = pygame.sprite.Sprite()
        stage_number_sprite.image = self.my_font.render(str(self.current_stage_num), False, (30, 30, 30))
        stage_number_sprite.rect = stage_number_sprite.image.get_rect(topleft=(720, 65 + 24 * 20))
        self.score_board_group.add(stage_number_sprite)

    def _generate_stage(self, stage_num):
        if self.should_generate_stage:
            # 获取每关敌方坦克信息
            with open(f"assets/stages/stage_{stage_num}/enemy_tank", "r") as f:
                line = f.readlines()[0]
                self.all_enemy_tanks = line.split()
            # 生成地图
            self.screen.blit(self.background_image, (0, 0))
            self.landscape_group, self.prop_forbidden_landscape_group, self.home = \
                MapGenerator(stage_num).run(self.screen)
            # 生成计分板
            self._generate_score_board()

            self.should_generate_stage = False

    def _generate_player_tanks(self):
        if not self.player1_tank and self.player1_live_count:
            self.player1_tank = PlayerTank(Player.PLAYER1, self.gunfire_sound)
            self.player_tank_group.add(self.player1_tank)
            self.tank_group.add(self.player1_tank)
        if not self.player_tank_group.has(self.player1_tank) and self.player1_live_count:
            self.player1_tank = None
            self.player1_live_count -= 1
            self.player1_live_count_sprite.image = \
                self.my_font.render(str(self.player1_live_count), False, (10, 10, 10))
        if not self.player2_tank and self.player2_live_count:
            self.player2_tank = PlayerTank(Player.PLAYER2, self.gunfire_sound)
            self.player_tank_group.add(self.player2_tank)
            self.tank_group.add(self.player2_tank)
        if not self.player_tank_group.has(self.player2_tank) and self.player2_live_count:
            self.player2_tank = None
            self.player2_live_count -= 1
            self.player2_live_count_sprite.image = \
                self.my_font.render(str(self.player2_live_count), False, (10, 10, 10))
        if self.player1_live_count == 0 and self.player2_live_count == 0:
            self._game_over()

    def activate_prop(self, collided_sprites, player_tank):
        # 坦克升级
        if isinstance(collided_sprites[0], UpgradeProp):
            self.activate_common_prop_sound.play()
            player_tank.upgrade()
        # 坦克终极升级
        if isinstance(collided_sprites[0], UltimateUpgradeProp):
            self.activate_common_prop_sound.play()
            player_tank.upgrade(is_upgrade_top=True)
        # 坦克生命加一
        if isinstance(collided_sprites[0], HealthProp):
            self.activate_health_prop_sound.play()
            if player_tank.player == Player.PLAYER1:
                self.player1_live_count += 1
                self.player1_live_count_sprite.image = \
                    self.my_font.render(str(self.player1_live_count), False, (10, 10, 10))
            else:
                self.player2_live_count += 1
                self.player2_live_count_sprite.image = \
                    self.my_font.render(str(self.player2_live_count), False, (10, 10, 10))
        # 使用钢铁加固基地
        if isinstance(collided_sprites[0], ReinforceProp):
            self.activate_common_prop_sound.play()
            reinforce_left_top_coordinates = [(339, 603), (339, 579), (339, 555), (315, 555), (291, 555), (267, 555),
                                            (267, 579), (267, 603)]
            for coordinate in reinforce_left_top_coordinates:
                steel = Steel()
                steel.rect.left, steel.rect.top = coordinate
                self.landscape_group.add(steel)
        # 消灭所有正在活动的敌方坦克
        if isinstance(collided_sprites[0], BoomProp):
            if not self.enemy_tank_group and not self.all_enemy_tanks:
                return
            self.tank_explosion_sound.play()
            for enemy_tank in self.enemy_tank_group:
                self.enemy_tank_group.remove(enemy_tank)
                self.tank_group.remove(enemy_tank)
                self.tank_explosion_sound.play()
                explosion_animation_sprite = AnimationSprite(
                    self.large_explosion_images,
                    pos=enemy_tank.rect.center,
                )
                explosion_animation_sprite.start()
                self.non_collidable_animation_group.add(explosion_animation_sprite)
        # 暂停所有正在活动的敌方坦克
        if isinstance(collided_sprites[0], PauseProp):
            self.activate_pause_prop_sound.play()
            self.pause_start_time = pygame.time.get_ticks()
            self.is_pause_moving = True
        # 使用盔甲
        if isinstance(collided_sprites[0], ShieldProp):
            self.activate_common_prop_sound.play()
            if player_tank.shield:
                player_tank.shield_active_time = pygame.time.get_ticks()
                return
            shield = Shield(player_tank.speed)
            shield.rect.left, shield.rect.top = player_tank.rect.topleft
            player_tank.shield = shield
            player_tank.shield_active_time = pygame.time.get_ticks()
            self.shield_group.add(player_tank.shield)

    def _control(self, joystick_shoot_event):
        if self.is_game_over:
            return
        keys = pygame.key.get_pressed()
        can_move = True
        collided_sprites = None
        if self.player1_tank:
            # 玩家一发射
            if keys[pygame.K_SPACE]:
                bullet = self.player1_tank.shoot()
                if bullet:
                    self.player_bullet_group.add(bullet)
            # 玩家一移动
            if not self.player1_move_delay:
                # 注意，这边几个条件判断需要使用 if ... elif ... elif 的形式，不能使用多个 if 并列的形式，否则可能导致坦克卡地形。
                if keys[pygame.K_w]:
                    if (self.player1_tank.rect.top - 3) % 24 == 0:
                        self.player1_move_delay = 7
                    else:
                        self.player1_move_delay = 3
                    can_move, collided_sprites = self.player1_tank.move(
                        direction=Direction.UP,
                        tank_group=self.tank_group,
                        landscape_group=self.landscape_group,
                        animation_group=self.collidable_animation_group,
                        prop_group=self.prop_group
                    )
                    self.player1_last_direction = Direction.UP
                elif keys[pygame.K_s]:
                    if (self.player1_tank.rect.top - 3) % 24 == 0:
                        self.player1_move_delay = 7
                    else:
                        self.player1_move_delay = 3
                    can_move, collided_sprites = self.player1_tank.move(
                        direction=Direction.DOWN,
                        tank_group=self.tank_group,
                        landscape_group=self.landscape_group,
                        animation_group=self.collidable_animation_group,
                        prop_group=self.prop_group
                    )
                    self.player1_last_direction = Direction.DOWN
                elif keys[pygame.K_a]:
                    if (self.player1_tank.rect.left - 3) % 24 == 0:
                        self.player1_move_delay = 7
                    else:
                        self.player1_move_delay = 3
                    can_move, collided_sprites = self.player1_tank.move(
                        direction=Direction.LEFT,
                        tank_group=self.tank_group,
                        landscape_group=self.landscape_group,
                        animation_group=self.collidable_animation_group,
                        prop_group=self.prop_group
                    )
                    self.player1_last_direction = Direction.LEFT
                elif keys[pygame.K_d]:
                    if (self.player1_tank.rect.left - 3) % 24 == 0:
                        self.player1_move_delay = 7
                    else:
                        self.player1_move_delay = 3
                    can_move, collided_sprites = self.player1_tank.move(
                        direction=Direction.RIGHT,
                        tank_group=self.tank_group,
                        landscape_group=self.landscape_group,
                        animation_group=self.collidable_animation_group,
                        prop_group=self.prop_group
                    )
                    self.player1_last_direction = Direction.RIGHT
            if self.player1_move_delay:
                self.player1_move_delay -= 1
                can_move, collided_sprites = self.player1_tank.move(
                    direction=self.player1_last_direction,
                    tank_group=self.tank_group,
                    landscape_group=self.landscape_group,
                    animation_group=self.collidable_animation_group,
                    prop_group=self.prop_group
                )
            if not can_move and collided_sprites is not None and isinstance(collided_sprites[0], BaseProp):
                self.activate_prop(collided_sprites, self.player1_tank)
        can_move = True
        collided_sprites = None
        if self.player2_tank:
            # 判断是否连接手柄
            if self.joystick:
                # 玩家二发射
                if joystick_shoot_event:
                    bullet = self.player2_tank.shoot()
                    if bullet:
                        self.player_bullet_group.add(bullet)
                # 玩家二移动
                if not self.player2_move_delay:
                    x = self.joystick.get_axis(0)
                    y = self.joystick.get_axis(1)
                    x = x if abs(x) > 0.1 else 0
                    y = y if abs(y) > 0.1 else 0
                    if abs(x) >= abs(y) and x != 0:
                        x = 1 if x > 0 else -1
                        y = 0
                    if abs(x) < abs(y):
                        y = 1 if y > 0 else -1
                        x = 0
                    if (x, y) == Direction.UP or (x, y) == Direction.DOWN:
                        if (self.player2_tank.rect.top - 3) % 24 == 0:
                            self.player2_move_delay = 7
                        else:
                            self.player2_move_delay = 3
                    elif (x, y) == Direction.LEFT or (x, y) == Direction.RIGHT:
                        if (self.player2_tank.rect.left - 3) % 24 == 0:
                            self.player2_move_delay = 7
                        else:
                            self.player2_move_delay = 3
                    can_move, collided_sprites = self.player2_tank.move(
                        direction=(x, y),
                        tank_group=self.tank_group,
                        landscape_group=self.landscape_group,
                        animation_group=self.collidable_animation_group,
                        prop_group=self.prop_group
                    )
                    self.player2_move_delay = 7
                    self.player2_last_direction = (x, y)
                if self.player2_move_delay:
                    self.player2_move_delay -= 1
                    can_move, collided_sprites = self.player2_tank.move(
                        direction=self.player2_last_direction,
                        tank_group=self.tank_group,
                        landscape_group=self.landscape_group,
                        animation_group=self.collidable_animation_group,
                        prop_group=self.prop_group
                    )
            else:
                # 玩家二发射
                if keys[pygame.K_PAGEDOWN]:
                    bullet = self.player2_tank.shoot()
                    if bullet:
                        self.player_bullet_group.add(bullet)
                # 玩家二移动
                if not self.player2_move_delay:
                    if keys[pygame.K_UP]:
                        if (self.player2_tank.rect.top - 3) % 24 == 0:
                            self.player2_move_delay = 7
                        else:
                            self.player2_move_delay = 3
                        can_move, collided_sprites = self.player2_tank.move(
                            direction=Direction.UP,
                            tank_group=self.tank_group,
                            landscape_group=self.landscape_group,
                            animation_group=self.collidable_animation_group,
                            prop_group=self.prop_group
                        )
                        self.player2_last_direction = Direction.UP
                    elif keys[pygame.K_DOWN]:
                        if (self.player2_tank.rect.top - 3) % 24 == 0:
                            self.player2_move_delay = 7
                        else:
                            self.player2_move_delay = 3
                        can_move, collided_sprites = self.player2_tank.move(
                            direction=Direction.DOWN,
                            tank_group=self.tank_group,
                            landscape_group=self.landscape_group,
                            animation_group=self.collidable_animation_group,
                            prop_group=self.prop_group
                        )
                        self.player2_last_direction = Direction.DOWN
                    elif keys[pygame.K_LEFT]:
                        if (self.player2_tank.rect.left - 3) % 24 == 0:
                            self.player2_move_delay = 7
                        else:
                            self.player2_move_delay = 3
                        can_move, collided_sprites = self.player2_tank.move(
                            direction=Direction.LEFT,
                            tank_group=self.tank_group,
                            landscape_group=self.landscape_group,
                            animation_group=self.collidable_animation_group,
                            prop_group=self.prop_group
                        )
                        self.player2_last_direction = Direction.LEFT
                    elif keys[pygame.K_RIGHT]:
                        if (self.player2_tank.rect.left - 3) % 24 == 0:
                            self.player2_move_delay = 7
                        else:
                            self.player2_move_delay = 3
                        can_move, collided_sprites = self.player2_tank.move(
                            direction=Direction.RIGHT,
                            tank_group=self.tank_group,
                            landscape_group=self.landscape_group,
                            animation_group=self.collidable_animation_group,
                            prop_group=self.prop_group
                        )
                        self.player2_last_direction = Direction.RIGHT
                if self.player2_move_delay:
                    self.player2_move_delay -= 1
                    can_move, collided_sprites = self.player2_tank.move(
                        direction=self.player2_last_direction,
                        tank_group=self.tank_group,
                        landscape_group=self.landscape_group,
                        animation_group=self.collidable_animation_group,
                        prop_group=self.prop_group
                    )
            if not can_move and collided_sprites is not None and isinstance(collided_sprites[0], BaseProp):
                self.activate_prop(collided_sprites, self.player2_tank)

    def _generate_enemy_tanks(self):
        # 当场上已经有四辆坦克 或 当前关卡已无坦克可以生成时，直接返回不生成坦克
        current_time = pygame.time.get_ticks()
        if len(self.enemy_tank_group) >= 4 or not self.all_enemy_tanks:
            return
        # 坦克最需要等待指定时间后才会生成
        if current_time - self.last_enemy_tank_appear_time < self.enemy_tank_appear_interval:
            return
        enemy_tank_spawn_rect = EnemyTankSpawn()[self.enemy_tank_spawn_index]
        appear_animation_sprite = AnimationSprite(
            self.appear_images,
            pos=enemy_tank_spawn_rect.center,
            frame_duration=100,
            loop_count=1
        )
        # 如果敌方坦克出生点上有坦克存在，则在其他出生点上出生
        if pygame.sprite.spritecollide(appear_animation_sprite, self.tank_group, False):
            self.enemy_tank_spawn_index = (self.enemy_tank_spawn_index + 1) % len(EnemyTankSpawn())
            return
        appear_animation_sprite.start()
        for appear_animation_sprite in self.collidable_animation_group:
            if appear_animation_sprite.is_finished:
                self.last_enemy_tank_appear_time = pygame.time.get_ticks()
                self.enemy_tank_spawn_index = (self.enemy_tank_spawn_index + 1) % len(EnemyTankSpawn())
                self.enemy_icon_group.pop()
                tank_type = self.all_enemy_tanks.pop(0).strip()
                enemy_tank = TANK_MAP.get(tank_type)()
                enemy_tank.rect.left = appear_animation_sprite.rect.left
                enemy_tank.rect.top = appear_animation_sprite.rect.top
                self.enemy_tank_group.add(enemy_tank)
                self.tank_group.add(enemy_tank)
                appear_animation_sprite.can_be_deleted = True
        self.collidable_animation_group.add(appear_animation_sprite)

    def _control_enemy_tank(self):
        if self.is_pause_moving:
            current_time = pygame.time.get_ticks()
            if current_time - self.pause_start_time > self.pause_duration:
                self.is_pause_moving = False
            return
        for enemy_tank in self.enemy_tank_group:
            enemy_tank.auto_move(self.tank_group, self.landscape_group, self.collidable_animation_group)
            enemy_bullet = enemy_tank.auto_shoot()
            if enemy_bullet:
                self.enemy_bullet_group.add(enemy_bullet)

    def _update_screen(self):
        # 清除上一帧的图像
        self.enemy_icon_group.clear(self.screen, self.background_image)
        self.score_board_group.clear(self.screen, self.background_image)
        self.landscape_group.clear(self.screen, self.background_image)
        self.tank_group.clear(self.screen, self.background_image)
        self.shield_group.clear(self.screen, self.background_image)
        self.player_bullet_group.clear(self.screen, self.background_image)
        self.enemy_bullet_group.clear(self.screen, self.background_image)
        self.prop_group.clear(self.screen, self.background_image)
        self.collidable_animation_group.clear(self.screen, self.background_image)
        self.non_collidable_animation_group.clear(self.screen, self.background_image)
        # 更新当前帧的图像
        if self.enemy_icon_group:
            self.enemy_icon_group.update()
            self.enemy_icon_group.draw(self.screen)
        if self.score_board_group:
            self.score_board_group.update()
            self.score_board_group.draw(self.screen)
        if self.tank_group:
            self.tank_group.update()
            self.tank_group.draw(self.screen)
        if self.shield_group:
            # 检测坦克护盾是否失效
            for player_tank in self.player_tank_group:
                if player_tank.shield and pygame.time.get_ticks() - player_tank.shield_active_time > player_tank.shield_duration:
                    player_tank.shield.kill()
                    player_tank.shield = None
            # 坦克护盾动画帧切换
            for shield in self.shield_group:
                if pygame.time.get_ticks() - shield.last_move_animation_change_time > shield.move_animation_interval:
                    if shield.image == shield.shield_image_02:
                        shield.image = shield.shield_image_01
                    else:
                        shield.image = shield.shield_image_02
            self.shield_group.update()
            self.shield_group.draw(self.screen)
        # 地形组要在坦克组之后，子弹组之前绘制
        if self.landscape_group:
            self.landscape_group.update()
            self.landscape_group.draw(self.screen)
        if self.player_bullet_group:
            bullet_sprites = self.player_bullet_group.update(
                self.landscape_group,
                prop_forbidden_landscape_group=self.prop_forbidden_landscape_group,
                tank_group=self.tank_group,
                player_tank_group=self.player_bullet_group,
                enemy_tank_group=self.enemy_tank_group,
                enemy_bullet_group=self.enemy_bullet_group,
                prop_group=self.prop_group,
            )
            self.player_bullet_group.draw(self.screen)
            for bullet_sprite in bullet_sprites:
                if not bullet_sprite.is_alive:
                    # 玩家坦克子弹击中地形，地图边界和敌军子弹时，出现小型爆炸动画
                    if bullet_sprite.explosion_type == ExplosionType.SMALL:
                        self.bullet_impact_sound.play()
                        explosion_animation_sprite = AnimationSprite(
                            self.small_explosion_images,
                            pos=bullet_sprite.rect.center,
                        )
                        explosion_animation_sprite.start()
                        self.non_collidable_animation_group.add(explosion_animation_sprite)
                    # 玩家坦克子弹击中敌方坦克时，出现大型爆炸动画
                    elif bullet_sprite.explosion_type == ExplosionType.LARGE:
                        self.tank_explosion_sound.play()
                        explosion_animation_sprite = AnimationSprite(
                            self.large_explosion_images,
                            pos=bullet_sprite.rect.center,
                        )
                        explosion_animation_sprite.start()
                        self.non_collidable_animation_group.add(explosion_animation_sprite)
                    # 记录玩家击杀记录
                    if bullet_sprite.destroyed_enemy_tank:
                        if bullet_sprite.owner.player == Player.PLAYER1:
                            if isinstance(bullet_sprite.destroyed_enemy_tank, Enemy1Tank) or \
                                    isinstance(bullet_sprite.destroyed_enemy_tank, EnemyPropTank):
                                self.p1_kill_info[Enemy1Tank]["kill_count"] += 1
                            elif isinstance(bullet_sprite.destroyed_enemy_tank, Enemy2Tank):
                                self.p1_kill_info[Enemy2Tank]["kill_count"] += 1
                            elif isinstance(bullet_sprite.destroyed_enemy_tank, Enemy3Tank):
                                self.p1_kill_info[Enemy3Tank]["kill_count"] += 1
                            elif isinstance(bullet_sprite.destroyed_enemy_tank, Enemy4Tank):
                                self.p1_kill_info[Enemy4Tank]["kill_count"] += 1
                        elif bullet_sprite.owner.player == Player.PLAYER2:
                            if isinstance(bullet_sprite.destroyed_enemy_tank, Enemy1Tank) or \
                                    isinstance(bullet_sprite.destroyed_enemy_tank, EnemyPropTank):
                                self.p2_kill_info[Enemy1Tank]["kill_count"] += 1
                            elif isinstance(bullet_sprite.destroyed_enemy_tank, Enemy2Tank):
                                self.p2_kill_info[Enemy2Tank]["kill_count"] += 1
                            elif isinstance(bullet_sprite.destroyed_enemy_tank, Enemy3Tank):
                                self.p2_kill_info[Enemy3Tank]["kill_count"] += 1
                            elif isinstance(bullet_sprite.destroyed_enemy_tank, Enemy4Tank):
                                self.p2_kill_info[Enemy4Tank]["kill_count"] += 1
        if self.enemy_bullet_group:
            bullet_sprites = self.enemy_bullet_group.update(
                self.landscape_group,
                player_tank_group=self.player_tank_group,
                player_bullet_group=self.player_bullet_group
            )
            self.enemy_bullet_group.draw(self.screen)
            for bullet_sprite in bullet_sprites:
                # 敌方坦克的子弹只有击中玩家坦克时，才会出现爆炸的动画，其他情况则不会
                if not bullet_sprite.is_alive and bullet_sprite.explosion_type == ExplosionType.LARGE:
                    self.tank_explosion_sound.play()
                    explosion_animation_sprite = AnimationSprite(
                        self.large_explosion_images,
                        pos=bullet_sprite.rect.center,
                    )
                    explosion_animation_sprite.start()
                    self.non_collidable_animation_group.add(explosion_animation_sprite)
        if self.prop_group:
            self.prop_group.update()
            self.prop_group.draw(self.screen)
        if self.non_collidable_animation_group:
            finished_non_collidable_animations = []
            for non_collidable_animation in self.non_collidable_animation_group:
                if non_collidable_animation.is_finished:
                    finished_non_collidable_animations.append(non_collidable_animation)
            for finished_non_collidable_animation in finished_non_collidable_animations:
                self.non_collidable_animation_group.remove(finished_non_collidable_animation)
            self.non_collidable_animation_group.update()
            self.non_collidable_animation_group.draw(self.screen)
        if self.collidable_animation_group:
            finished_collidable_animations = []
            for collidable_animation in self.collidable_animation_group:
                if collidable_animation.is_finished and collidable_animation.can_be_deleted:
                    finished_collidable_animations.append(collidable_animation)
            for finished_collidable_animation in finished_collidable_animations:
                self.collidable_animation_group.remove(finished_collidable_animation)
            self.collidable_animation_group.update()
            self.collidable_animation_group.draw(self.screen)
        pygame.display.flip()

    def _game_over(self):
        if not self.is_game_over:
            self.tank_explosion_sound.play()
            self.is_game_over = True
            self.game_over_countdown_start_time = pygame.time.get_ticks()
            self.game_over_sprite.image = self.game_over_image
            self.game_over_sprite.rect = self.game_over_image.get_rect()
            self.game_over_sprite.rect.center = (315, 640 + self.game_over_sprite.rect.height / 2)
            self.game_over_group.add(self.game_over_sprite)
        if self.game_over_group:
            target_center_y = 315
            move_speed = 3
            if self.game_over_sprite.rect.centery > target_center_y:
                self.game_over_sprite.rect.centery -= move_speed
            self.game_over_group.clear(self.screen, self.background_image)
            self.game_over_group.update()
            self.game_over_group.draw(self.screen)
        if pygame.time.get_ticks() - self.game_over_countdown_start_time > self.game_over_countdown:
            self.game_over_sound.play()
            self.game_over_countdown = 10000000000000

    def generate_stage_result_screen(self):
        if self.step is GameScreen.RESULTS and not self.is_resulting:
            self.is_resulting = True
            # 填充背景
            self.last_resulting_animation_time = pygame.time.get_ticks()
            self.screen.blit(self.background3_image, (0, 0))

            # HI-SCORE 红色
            word_hi_score_image = self.my_result_font.render("HI-SCORE", False, (255, 0, 0))
            self.screen.blit(word_hi_score_image, (200, 68))
            # 20000 橙色
            word_20000_image = self.my_result_font.render("20000", False, (255, 204, 0))
            self.screen.blit(word_20000_image, (412, 68))
            # STAGE X 白色
            word_stage_x_image = \
                self.my_result_font.render(f"STAGE    {self.current_stage_num}", False, (255, 255, 255))
            self.screen.blit(word_stage_x_image, (310, 120))
            # PLAYER-I 红色
            word_player_i_image = self.my_result_font.render("PLAYER-I", False, (255, 0, 0))
            self.screen.blit(word_player_i_image, (140, 164))
            # PLAYER-II 红色
            word_player_ii_image = self.my_result_font.render("PLAYER-II", False, (255, 0, 0))
            self.screen.blit(word_player_ii_image, (491, 164))
            # PTS 白色 *8
            word_pts_image = self.my_result_font.render("PTS", False, (255, 255, 255))
            self.screen.blit(word_pts_image, (192, 266))
            self.screen.blit(word_pts_image, (192, 335))
            self.screen.blit(word_pts_image, (192, 404))
            self.screen.blit(word_pts_image, (192, 474))
            self.screen.blit(word_pts_image, (521, 266))
            self.screen.blit(word_pts_image, (521, 335))
            self.screen.blit(word_pts_image, (521, 404))
            self.screen.blit(word_pts_image, (521, 474))
            # 敌军坦克图标
            self.screen.blit(self.enemy1_tank_image, (351, 258))
            self.screen.blit(self.enemy2_tank_image, (351, 327))
            self.screen.blit(self.enemy3_tank_image, (351, 396))
            self.screen.blit(self.enemy4_tank_image, (351, 465))
            # 白线
            white_line_image = pygame.Surface((190, 3))
            white_line_image.fill((255, 255, 255))
            self.screen.blit(white_line_image, (278, 527))
            # TOTAL 白色 *2
            word_pts_image = self.my_result_font.render("TOTAL", False, (255, 255, 255))
            self.screen.blit(word_pts_image, (171, 524))
            self.screen.blit(word_pts_image, (489, 524))
            # 白色箭头 *8
            self.screen.blit(self.arrow1_image, (330, 275))
            self.screen.blit(self.arrow1_image, (330, 344))
            self.screen.blit(self.arrow1_image, (330, 413))
            self.screen.blit(self.arrow1_image, (330, 483))
            self.screen.blit(self.arrow2_image, (402, 275))
            self.screen.blit(self.arrow2_image, (402, 344))
            self.screen.blit(self.arrow2_image, (402, 413))
            self.screen.blit(self.arrow2_image, (402, 483))
            # 玩家一总分
            player1_score_image = \
                self.my_result_font.render(str(self.player1_score), False, (255, 204, 0))
            self.screen.blit(player1_score_image, (139, 209))
            # 玩家二总分
            player2_score_image = \
                self.my_result_font.render(str(self.player2_score), False, (255, 204, 0))
            self.screen.blit(player2_score_image, (494, 209))
            pygame.display.flip()

        if self.step is GameScreen.RESULTS:
            enemy_tank_types = [Enemy1Tank, Enemy2Tank, Enemy3Tank, Enemy4Tank]
            while self.resulting_idx < 4 and \
                    pygame.time.get_ticks() - self.last_resulting_animation_time > self.resulting_animation_duration:

                self.result_sound.play()

                self.last_resulting_animation_time = pygame.time.get_ticks()
                self.resulting_animation_duration = 200
                enemy_tank_type = enemy_tank_types[self.resulting_idx]
                p1_killed_enemy_x_info = self.p1_kill_info.get(enemy_tank_type)
                p2_killed_enemy_x_info = self.p2_kill_info.get(enemy_tank_type)

                if not self.is_player1_resulted:
                    # 渲染玩家一击杀坦克x的数量
                    p1_resulting_temp_count_image = self.my_result_font.render(
                        str(self.p1_resulting_temp_count), False, (255, 255, 255)
                    )
                    # 覆盖上一次的画面
                    cover_image = pygame.Surface((20, 22))
                    cover_image.fill((0, 0, 0))
                    self.screen.blit(cover_image, p1_killed_enemy_x_info.get("kill_count_rect"))
                    self.screen.blit(
                        p1_resulting_temp_count_image, p1_killed_enemy_x_info.get("kill_count_rect")
                    )

                    # 渲染玩家一击杀坦克x的分数
                    p1_current_killed_enemy_score = self.p1_resulting_temp_count * enemy_tank_type.score
                    p1_current_killed_enemy_score_image = self.my_result_font.render(
                        str(p1_current_killed_enemy_score), False, (255, 255, 255)
                    )
                    # 覆盖上一次的画面
                    cover_image = pygame.Surface(p1_current_killed_enemy_score_image.get_rect().size)
                    cover_image.fill((0, 0, 0))
                    self.screen.blit(cover_image, p1_killed_enemy_x_info.get("kill_score_rect"))
                    self.screen.blit(
                        p1_current_killed_enemy_score_image, p1_killed_enemy_x_info.get("kill_score_rect")
                    )

                    if self.p1_resulting_temp_count < p1_killed_enemy_x_info.get("kill_count"):
                        self.p1_resulting_temp_count += 1
                    else:
                        self.p1_resulting_temp_count = 0
                        self.is_player1_resulted = True
                        self.player1_stage_score += p1_current_killed_enemy_score

                if not self.is_player2_resulted:
                    # 渲染玩家二击杀坦克x的数量
                    p2_resulting_temp_count_image = self.my_result_font.render(
                        str(self.p2_resulting_temp_count), False, (255, 255, 255)
                    )
                    # 覆盖上一次的画面
                    cover_image = pygame.Surface((20, 22))
                    cover_image.fill((0, 0, 0))
                    self.screen.blit(cover_image, p2_killed_enemy_x_info.get("kill_count_rect"))
                    self.screen.blit(
                        p2_resulting_temp_count_image, p2_killed_enemy_x_info.get("kill_count_rect")
                    )

                    # 渲染玩家二击杀坦克x的分数
                    p2_current_killed_enemy_score = self.p2_resulting_temp_count * enemy_tank_type.score
                    p2_current_killed_enemy_score_image = self.my_result_font.render(
                        str(p2_current_killed_enemy_score), False, (255, 255, 255)
                    )
                    # 覆盖上一次的画面
                    cover_image = pygame.Surface(p2_current_killed_enemy_score_image.get_rect().size)
                    cover_image.fill((0, 0, 0))
                    self.screen.blit(cover_image, p2_killed_enemy_x_info.get("kill_score_rect"))
                    self.screen.blit(
                        p2_current_killed_enemy_score_image, p2_killed_enemy_x_info.get("kill_score_rect")
                    )

                    if self.p2_resulting_temp_count < p2_killed_enemy_x_info.get("kill_count"):
                        self.p2_resulting_temp_count += 1
                    else:
                        self.p2_resulting_temp_count = 0
                        self.is_player2_resulted = True
                        self.player2_stage_score += p2_current_killed_enemy_score

                if self.is_player1_resulted and self.is_player2_resulted:
                    self.is_player1_resulted = False
                    self.is_player2_resulted = False
                    self.resulting_idx += 1
                    self.resulting_animation_duration = 500
                pygame.display.flip()
                return

            if pygame.time.get_ticks() - self.last_resulting_animation_time > self.resulting_animation_duration and \
                    not self.should_update_total_score and not self.should_start_new_stage:
                # 渲染玩家一当前关卡分数
                player1_stage_score_image = \
                    self.my_result_font.render(str(self.player1_stage_score), False, (255, 255, 255))
                self.screen.blit(player1_stage_score_image, (197, 565))
                # 渲染玩家二当前关卡分数
                player2_stage_score_image = \
                    self.my_result_font.render(str(self.player2_stage_score), False, (255, 255, 255))
                self.screen.blit(player2_stage_score_image, (513, 565))
                self.should_update_total_score = True
                pygame.display.flip()
                return

            if pygame.time.get_ticks() - self.last_resulting_animation_time > self.resulting_animation_duration and \
                    self.should_update_total_score and not self.should_start_new_stage:
                # 更新玩家一总分
                self.player1_score += self.player1_stage_score
                player1_score_image = \
                    self.my_result_font.render(str(self.player1_score), False, (255, 204, 0))
                cover_image = pygame.Surface(player1_score_image.get_rect().size)
                cover_image.fill((0, 0, 0))
                self.screen.blit(cover_image, (139, 209))
                self.screen.blit(player1_score_image, (139, 209))
                # 更新玩家二总分
                self.player2_score += self.player2_stage_score
                player2_score_image = \
                    self.my_result_font.render(str(self.player2_score), False, (255, 204, 0))
                self.screen.blit(cover_image, (494, 209))
                self.screen.blit(player2_score_image, (494, 209))
                self.should_update_total_score = False
                self.should_start_new_stage = True
                self.resulting_animation_duration = 3000
                pygame.display.flip()

            if pygame.time.get_ticks() - self.last_resulting_animation_time > self.resulting_animation_duration and \
                    self.should_start_new_stage:
                self.step = GameScreen.TRANSITION
                self.current_stage_num += 1
                if self.player1_tank:
                    self.player1_tank.reset()
                if self.player2_tank:
                    self.player2_tank.reset()
                self._init_resulting()
                self._init_group(is_first=False)

    def start(self):
        clock = pygame.time.Clock()

        # 检查手柄
        self._check_joystick()

        while True:
            joystick_shoot_event = None
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()
                if event.type == pygame.JOYBUTTONDOWN and event.button == 0 and self.joystick:
                    joystick_shoot_event = event

            # 生成关卡加载页面
            self._generate_stage_loading_screen()

            if self.step is GameScreen.IN_GAME:
                # 生成关卡
                self._generate_stage(self.current_stage_num)

                # 生成玩家坦克
                self._generate_player_tanks()

                # 玩家操作控制
                self._control(joystick_shoot_event)

                # 生成敌方坦克
                self._generate_enemy_tanks()

                # 敌方坦克自主移动和射击
                self._control_enemy_tank()

                # 更新画面
                self._update_screen()

                # 检测基地状态
                if self.home not in self.landscape_group:
                    self._game_over()

                # 检测敌方坦克是否被全部消灭
                if not self.enemy_tank_group.sprites() and not self.all_enemy_tanks:
                    self.step = GameScreen.RESULTS

            if self.step is GameScreen.RESULTS:
                self.generate_stage_result_screen()

            clock.tick(60)


if __name__ == '__main__':
    GameInitializer().start()
